/// <reference name="MicrosoftAjax.js"/>
    
Type.registerNamespace("ImageCropper");

ImageCropper.BaseBehavior = function(element) {
    ImageCropper.BaseBehavior.initializeBase(this, [element]);
    this.image = null;
    this.currentBounds = null;
    this.cropper = null;
    this.moving = null;
    this.resizing = null;
}

ImageCropper.BaseBehavior.prototype = {
    initialize: function() {
        ImageCropper.BaseBehavior.callBaseMethod(this, 'initialize');
        this._onmousedownDelegate = Function.createDelegate(this, this._onmousedown);
        this._onmousemoveDelegate = Function.createDelegate(this, this._onmousemove);
        this._onmouseupDelegate = Function.createDelegate(this, this._onmouseup);    
        this._onselectstartDelegate = Function.createDelegate(this, this._onselectstart);       
    },

    dispose: function() {       
        this._onmousedownDelegate = null;
        this._onmousemoveDelegate = null;
        this._onmouseupDelegate = null;
        this._onselectstartDelegate = null;
         
        ImageCropper.BaseBehavior.callBaseMethod(this, 'dispose');
    },
     
    updateBounds : function(bounds){
        var imageBounds = Sys.UI.DomElement.getBounds(this.image);
        var heightBorders = this.cropper.offsetHeight - this.cropper.clientHeight;  
        var widthBorders = this.cropper.offsetWidth - this.cropper.clientWidth;   

        if (this.resizing)
        {   
            //max
            bounds.width = bounds.x + bounds.width > imageBounds.x + imageBounds.width ? imageBounds.x + imageBounds.width - bounds.x : bounds.width;
            bounds.height = bounds.y + bounds.height > imageBounds.y + imageBounds.height ? imageBounds.y + imageBounds.height - bounds.y : bounds.height;  
            //min
            bounds.width = bounds.x < imageBounds.x ? bounds.x + bounds.width - imageBounds.x : bounds.width;
            bounds.height = bounds.y < imageBounds.y ? bounds.y + bounds.height - imageBounds.y : bounds.height;       
        }
           
        bounds.x = bounds.x < imageBounds.x ? imageBounds.x : bounds.x;
        bounds.y = bounds.y < imageBounds.y ? imageBounds.y : bounds.y;  
              
        if (this.moving)
        {
            //max
            bounds.x = bounds.x + bounds.width > imageBounds.x + imageBounds.width ? imageBounds.x + imageBounds.width - bounds.width : bounds.x;
            bounds.y = bounds.y + bounds.height > imageBounds.y + imageBounds.height ? imageBounds.y + imageBounds.height - bounds.height : bounds.y;
        }
        
        Sys.UI.DomElement.setLocation(this.cropper, bounds.x, bounds.y);  
        this.cropper.style.width = (bounds.width - widthBorders) < 0 ? (bounds.width  + "px") : ((bounds.width - widthBorders)  + "px");
        this.cropper.style.height = (bounds.height - heightBorders) < 0 ? (bounds.height  + "px") : ((bounds.height - heightBorders)  + "px");
    },
      
    _onselectstart : function(e) {
        e.preventDefault();
        return false;
    },  
    
    _onmousedown : function(e) {
        $addHandler(document, 'selectstart', this._onselectstartDelegate);
        if (Sys.Browser.agent === Sys.Browser.Opera) {
            $addHandler(document, 'mousedown', this._onselectstartDelegate);
        }
    },
    
    _onmousemove : function(e) {
    },
    
    _onmouseup: function(e) { 
        $removeHandler(document, 'selectstart', this._onselectstartDelegate);
        if (Sys.Browser.agent === Sys.Browser.Opera) {
            $removeHandler(document, 'mousedown', this._onselectstartDelegate);
        }    
    }, 
    
    get_Image : function() {
        return this.image;
    },
    
    set_Image : function(value) {
        this.image = value
    }
}

ImageCropper.BaseBehavior.registerClass('ImageCropper.BaseBehavior', AjaxControlToolkit.BehaviorBase)

ImageCropper.Movable = function(element) {
    ImageCropper.Movable.initializeBase(this, [element]);
}

ImageCropper.Movable.prototype = {
    initialize: function() {
        ImageCropper.Movable.callBaseMethod(this, 'initialize'); 
        this.cropper = this.get_element();
        $addHandler(this.cropper, "mousedown", this._onmousedownDelegate); 
        this.moving = false;
    },
    dispose: function() {       
        this.moving = null;
        $removeHandler(this.cropper, "mousedown", this._onmousedownDelegate); 
        ImageCropper.Movable.callBaseMethod(this, 'dispose');
    },  
    
    _onmousedown : function(e) {
        ImageCropper.Movable.callBaseMethod(this, '_onmousedown'); 
        $addHandler(document, 'mousemove', this._onmousemoveDelegate);
        $addHandler(document, 'mouseup', this._onmouseupDelegate);
        
        this.currentBounds = Sys.UI.DomElement.getBounds(this.cropper);
        this._offsetX = e.clientX - this.currentBounds.x;
        this._offsetY = e.clientY - this.currentBounds.y;
        this.moving = true;
        e.stopPropagation(); 
    },
    
    _onmouseup: function(e) {
        $removeHandler(document, 'mouseup', this._onmouseupDelegate);
        $removeHandler(document, 'mousemove', this._onmousemoveDelegate);
        ImageCropper.Movable.callBaseMethod(this, '_onmouseup'); 
        this.moving = false;
        e.stopPropagation(); 
    },
    
    _onmousemove: function(e) {
        if (this.moving)
        {
             var currentPoint = new Sys.UI.Point(e.clientX - this._offsetX, e.clientY - this._offsetY);  
             this.currentBounds.x = currentPoint.x;
             this.currentBounds.y = currentPoint.y;
             this.updateBounds(this.currentBounds);     
             this.raiseDrag();
         }
         e.stopPropagation(); 
    }, 
    
    add_drag : function(handler) {
        this.get_events().addHandler("drag", handler);
    },
    
    remove_drag : function(handler) {
        this.get_events().removeHandler("drag", handler);
    },
    
    raiseDrag : function() {
        var onDragHandler = this.get_events().getHandler("drag");
        if (onDragHandler) {
            onDragHandler(this, Sys.EventArgs.Empty);
        }
    }  
}

ImageCropper.Movable.registerClass('ImageCropper.Movable', ImageCropper.BaseBehavior);

ImageCropper.Resizable = function(element) {
    ImageCropper.Resizable.initializeBase(this, [element]);
    this.handleN = null;
    this.handleNE = null;
    this.handleE = null;
    this.handleSE = null;
    this.handleS = null;
    this.handleSW = null;
    this.handleW = null;
    this.handleNW = null;
    this.currentOrientation = null;
}

ImageCropper.Resizable.prototype = {
    initialize: function() {
        ImageCropper.Resizable.callBaseMethod(this, 'initialize');    
        this.cropper = this.get_element();  
        this._resizeHandleSet();         
        this.resizing = false;   
    },
    dispose: function() {     
        for (var i=0;i<this.handles.length;i++)
        {
            $removeHandler(this.handles[i], "mousedown", this._onmousedownDelegate); 
        }        
        ImageCropper.Resizable.callBaseMethod(this, 'dispose');
    },
    
    _resizeHandleSet : function(){         
        var constSuffix = "resizeHandle resizeHandle";
        var suffix = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"];   
        this.handles = [ this.handleN, this.handleNE, this.handleE, this.handleSE, this.handleS, this.handleSW, this.handleW, this.handleNW ];             
        for (var i=0;i<this.handles.length;i++)
        {
            this.handles[i] = document.createElement('div');           
            this.handles[i].setAttribute("orientation",i);//ImageCropper.Resizable.Orientation
            Sys.UI.DomElement.addCssClass(this.handles[i], constSuffix + suffix[i]);
            $addHandler(this.handles[i], "mousedown", this._onmousedownDelegate); 
            this.cropper.appendChild(this.handles[i]);                   
        }    
    },    
    
    _onmousedown : function(e) {
        $addHandler(document, 'mousemove', this._onmousemoveDelegate);
        $addHandler(document, 'mouseup', this._onmouseupDelegate);  
        this.currentBounds = Sys.UI.DomElement.getBounds(this.cropper);
        this.currentOrientation = e.target.getAttribute("orientation");
        this.resizing = true;
        ImageCropper.Resizable.callBaseMethod(this, '_onmousedown');   
        e.stopPropagation(); 
    },
    
    _onmousemove : function(e) {
        var currentPoint = new Sys.UI.Point(e.clientX, e.clientY);
        if (this.resizing)
        {           
            var offset = null;
            if (this.currentOrientation == ImageCropper.Resizable.Orientation.West ||
                this.currentOrientation == ImageCropper.Resizable.Orientation.SouthWest ||
                this.currentOrientation == ImageCropper.Resizable.Orientation.NorthWest)
            {    
                offset = this.currentBounds.x + this.currentBounds.width - currentPoint.x;
                if (offset >=0)
                {
                    this.currentBounds.width += this.currentBounds.x - currentPoint.x;
                    this.currentBounds.x = currentPoint.x; 
                }
            }          
            if (this.currentOrientation == ImageCropper.Resizable.Orientation.East ||
                this.currentOrientation == ImageCropper.Resizable.Orientation.NorthEast ||
                this.currentOrientation == ImageCropper.Resizable.Orientation.SouthEast)
            { 
                offset = currentPoint.x - this.currentBounds.x;
                if (offset >=0)
                {
                    this.currentBounds.width = offset;
                }
            }
            if (this.currentOrientation == ImageCropper.Resizable.Orientation.North ||
                this.currentOrientation == ImageCropper.Resizable.Orientation.NorthEast ||
                this.currentOrientation == ImageCropper.Resizable.Orientation.NorthWest)
            {
                offset = this.currentBounds.y + this.currentBounds.height - currentPoint.y;
                if (offset >=0)
                {
                    this.currentBounds.height += this.currentBounds.y - currentPoint.y;
                    this.currentBounds.y = currentPoint.y; 
                }                
            }
            if (this.currentOrientation == ImageCropper.Resizable.Orientation.South ||
                this.currentOrientation == ImageCropper.Resizable.Orientation.SouthEast ||
                this.currentOrientation == ImageCropper.Resizable.Orientation.SouthWest)
            {
                offset = currentPoint.y - this.currentBounds.y;
                if (offset >=0)
                {
                    this.currentBounds.height = offset;
                }            
            }
            this.updateBounds(this.currentBounds);
        }
        this.raiseResizing();
        e.stopPropagation(); 
    },
    
    _onmouseup: function(e) {
        var el = this.get_element();
        $removeHandler(document, 'mouseup', this._onmouseupDelegate);
        $removeHandler(document, 'mousemove', this._onmousemoveDelegate);
        this.currentBounds = Sys.UI.DomElement.getBounds(el);
        this.resizing = false;
        ImageCropper.Resizable.callBaseMethod(this, '_onmouseup'); 
        e.stopPropagation(); 
    },
    _reverseOrientation : function(orientation) {
        var newOrientation = null;
        switch(orientation)
        {
            case ImageCropper.Resizable.Orientation.North:
                break;
            case ImageCropper.Resizable.Orientation.NorthEast:
                break;
            case ImageCropper.Resizable.Orientation.East:
                break;
            case ImageCropper.Resizable.Orientation.SouthEast:
                break;
            case ImageCropper.Resizable.Orientation.South:
                break;
            case ImageCropper.Resizable.Orientation.SouthWest:
                break;
            case ImageCropper.Resizable.Orientation.West:
                break;
            case ImageCropper.Resizable.Orientation.NorthWest:
                break;
        }   
        return newOrientation;
    },
    
    _resetBounds : function() {
        var el = this.get_element();
        el.style.left = this.currentBounds.x + "px";
        el.style.top = this.currentBounds.y + "px";
        el.style.width = (this.currentBounds.width - this.widthBorders) < 0 ? (this.currentBounds.width  + "px") : ((this.currentBounds.width - this.widthBorders)  + "px");
        el.style.height = (this.currentBounds.height - this.heightBorders) < 0 ? (this.currentBounds.height  + "px") : ((this.currentBounds.height - this.heightBorders)  + "px");
    },
    
    _showHandles : function(isShow, specailHandle){
        if (specailHandle)
        {
            Sys.UI.DomElement.setVisible(specailHandle, isShow);
        }
        else// for all
        {
            for (var i=0;i<this.handles.length;i++)
            {
                 Sys.UI.DomElement.setVisible(this.handles[i], isShow);
            } 
        }
    },
    
    add_resizing : function(handler) {
        this.get_events().addHandler("resizing", handler);
    },
    
    remove_resizing : function(handler) {
        this.get_events().removeHandler("resizing", handler);
    },
    
    raiseResizing : function() {
        var onResizingHandler = this.get_events().getHandler("resizing");
        if (onResizingHandler) {
            onResizingHandler(this, Sys.EventArgs.Empty);
        }
    }
}
ImageCropper.Resizable.registerClass('ImageCropper.Resizable', ImageCropper.BaseBehavior);

ImageCropper.Resizable.Orientation = function() {
   throw Error.notImplemented
}
ImageCropper.Resizable.Orientation.prototype = {
    North      : 0, 
    NorthEast  : 1, 
    East       : 2, 
    SouthEast  : 3, 
    South      : 4, 
    SouthWest  : 5, 
    West       : 6, 
    NorthWest  : 7
}
ImageCropper.Resizable.Orientation.registerEnum("ImageCropper.Resizable.Orientation");

ImageCropper.Preview = function(element) {
    ImageCropper.Preview.initializeBase(this, [element]);
        //acceesor  
        this._image = null; 
        this._bounds = null;
        this._previewImage = null;
}

ImageCropper.Preview.prototype = {
    initialize: function() {
        ImageCropper.Preview.callBaseMethod(this, 'initialize');
        var el = this.get_element();
        this._previewImage = this._image.cloneNode(true);
        this._previewImage.style.position = "relative"; 

        el.style.position = "absolute";
        el.style.overflow = "hidden";
        el.appendChild(this._previewImage);
    },
    dispose: function() {       
        ImageCropper.Preview.callBaseMethod(this, 'dispose');
    },
    
    updateBounds:function(bounds){
        var el = this.get_element();
        var imgOffset = Sys.UI.DomElement.getLocation(this._image);

        var previewHeght = this.measurementToNumber(el.style.height);
        var previewWidth = this.measurementToNumber(el.style.width);

        this._previewImage.style.width = Math.ceil( previewWidth * (this._image.width / bounds.width) ) + "px";
        this._previewImage.style.height = Math.ceil( previewHeght * (this._image.height / bounds.height) ) + "px";
        this._previewImage.style.left = -Math.ceil( (bounds.x - imgOffset.x) / (bounds.width / previewWidth))  + "px";
        this._previewImage.style.top =  -Math.ceil( (bounds.y - imgOffset.y) / (bounds.height / previewHeght)) + "px";
    },
    
    get_Image : function() {
        return this._image;
    },
    set_Image : function(value) {
        this._image = value
    },
    
    get_Bounds : function() {
        return this._bounds;
    },
    set_Bounds : function(value) {
        this._bounds = value
    },
    
    //Utility
    measurementToNumber : function(m) {
        var temp = m.replace('px', '').trim();
        temp = temp ? temp : 0;
        return parseInt(temp);
    }    
}

ImageCropper.Preview.registerClass('ImageCropper.Preview', AjaxControlToolkit.BehaviorBase);

ImageCropper.ImageCropperBehavior = function(element) {
    ImageCropper.ImageCropperBehavior.initializeBase(this, [element]);
    this._preview = null;
}

ImageCropper.ImageCropperBehavior.prototype = {
    initialize: function() {
        ImageCropper.ImageCropperBehavior.callBaseMethod(this, 'initialize');
            var el = this.get_element();
            this.cropArea = document.createElement("div");
            Sys.UI.DomElement.addCssClass(this.cropArea, "element moveHandle");
            el.parentNode.insertBefore(this.cropArea,el);
            this.onCropDelegate = Function.createDelegate(this, this._oncrop);
            this.mover = $create(ImageCropper.Movable, {Image:el}, {drag: this.onCropDelegate}, null, this.cropArea);
            this.resizer = $create(ImageCropper.Resizable, {Image:el}, {resizing: this.onCropDelegate}, null, this.cropArea);
            if (this._preview)
            {
                this.previewer = $create(ImageCropper.Preview, {Image: el}, null, null, $get(this._preview));
            }
    },
    
    _oncrop : function(e) {
        this.previewer.updateBounds(Sys.UI.DomElement.getBounds(this.cropArea));
    },
    dispose: function() {       
        ImageCropper.ImageCropperBehavior.callBaseMethod(this, 'dispose');
    },
    
    get_Preview : function() {
        return this._preview;
    },
    set_Preview : function(value) {
        this._preview = value
    }
}

ImageCropper.ImageCropperBehavior.registerClass('ImageCropper.ImageCropperBehavior', AjaxControlToolkit.BehaviorBase)



